#include <glibmm-2.4/glibmm/main.h>
#include <gdkmm-3.0/gdkmm/rectangle.h>
#include <sstream>
#include "LienzoJuego.h"
#include "Trayectoria.h"
#include "Actor.h"
#include "Utilidad.h"
#include "Rol.h"
#include "Posicion.h"
#include "ActoresConstantes.h"
#include "UtilidadesConstantes.h"
#include "Cerdito.h"
#include "Catapulta.h"
#include "Piso.h"

using namespace TP::Juego::Arena::Actores;
using namespace TP::Juego::Arena::Utilidades;
using namespace TP::Threading;

LienzoJuego::LienzoJuego(Cliente* cliente, float fps) {
	_dibujador = new Dibujador(this);
	_cliente = cliente;
	_partida = NULL;

	Glib::signal_timeout().connect(
			sigc::mem_fun(*this, &LienzoJuego::on_timeout), 1000 / fps);
	add_events(Gdk::BUTTON_PRESS_MASK);
}

/****************************** Setters **************************************/

void LienzoJuego::SetImagenPajaroRojo(std::string pathImagen) {
	_imagenPajaroRojo = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenPajaroVerde(std::string pathImagen) {
	_imagenPajaroVerde = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenPajaroAzul(std::string pathImagen) {
	_imagenPajaroAzul = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenCerdito(std::string pathImagen) {
	_imagenCerdito = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenHuevoPoche(std::string pathImagen) {
	_imagenHuevoPoche = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenHuevoReloj(std::string pathImagen) {
	_imagenHuevoReloj = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenHuevoCodorniz(std::string pathImagen) {
	_imagenHuevoCodorniz = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenHuevoBlanco(std::string pathImagen) {
	_imagenHuevoBlanco = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenCajaMadera(std::string pathImagen) {
	_imagenCajaMadera = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenCajaMetal(std::string pathImagen) {
	_imagenCajaMetal = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenCajaVidrio(std::string pathImagen) {
	_imagenCajaVidrio = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenCatapulta(std::string pathImagen) {
	_imagenCatapulta = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenMonticuloHuevos(std::string pathImagen) {
	_imagenMonticuloHuevos = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenManzana(std::string pathImagen) {
	_imagenManzana = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenBanana(std::string pathImagen) {
	_imagenBanana = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenCereza(std::string pathImagen) {
	_imagenCereza = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

void LienzoJuego::SetImagenFondo(std::string pathImagen) {
	_fondo = Gdk::Pixbuf::create_from_file(pathImagen.c_str());
}

/*****************************************************************************/

bool LienzoJuego::on_draw(const Cairo::RefPtr<Cairo::Context>& context) {
	_dibujador->DibujarFondo(_fondo);

	if (_partida) {
		_mutex.lock();
        
		vector<Actor*>& vectorActores = _partida->ArenaJuego()->getActores();
		vector<Actor*>::iterator iteradorActores;

		for (iteradorActores = vectorActores.begin();
				iteradorActores != vectorActores.end();
				++iteradorActores) {
			Actor* actor = *iteradorActores;
			Posicion* posicion = actor->getTrayectoria()->getPosicion();

			long int x = posicion->X();
			long int y = posicion->Y();
			Rol* rol = actor->getRol();

			if (rol->Nombre() == PAJARITOROJO) {
				_dibujador->DibujarEntidad(_imagenPajaroRojo, x, y);
			}
			else if (rol->Nombre() == PAJARITOAZUL) {
				_dibujador->DibujarEntidad(_imagenPajaroAzul, x, y);
			}
			else if (rol->Nombre() == PAJARITOVERDE) {
				_dibujador->DibujarEntidad(_imagenPajaroVerde, x, y);
			}
			else if (rol->Nombre() == HUEVOBLANCO) {
				_dibujador->DibujarEntidad(_imagenHuevoBlanco, x, y);
			}
			else if (rol->Nombre() == HUEVOPOCHE) {
				_dibujador->DibujarEntidad(_imagenHuevoPoche, x, y);
			}
			else if (rol->Nombre() == HUEVOCODORNIZ) {
				_dibujador->DibujarEntidad(_imagenHuevoCodorniz, x, y);
			}
			else if (rol->Nombre() == HUEVORELOJ) {
				_dibujador->DibujarEntidad(_imagenHuevoReloj, x, y);
			}
		}

		// Dibujamos todos las utilidades
		vector<Utilidad*>& vectorUtilidades =
				_partida->ArenaJuego()->getUtilidades();
		vector<Utilidad*>::iterator iteradorUtilidades;

		for (iteradorUtilidades = vectorUtilidades.begin();
				iteradorUtilidades != vectorUtilidades.end();
				++iteradorUtilidades) {
			Utilidad* utilidad = *iteradorUtilidades;
			Posicion* posicion = utilidad->getPosicion();

			long int x = posicion->X();
			long int y = posicion->Y();
			Rol* rol = utilidad->getRol();

			if (rol->Nombre() == ROL_CAJA_MADERA) {
				_dibujador->DibujarEntidad(_imagenCajaMadera, x, y);
			}
			else if (rol->Nombre() == ROL_CAJA_VIDRIO) {
				_dibujador->DibujarEntidad(_imagenCajaVidrio, x, y);
			}
			else if (rol->Nombre() == ROL_CAJA_METAL) {
				_dibujador->DibujarEntidad(_imagenCajaMetal, x, y);
			}
			else if (rol->Nombre() == ROL_CATAPULTA) {
				_dibujador->DibujarEntidad(_imagenCatapulta, x, y);
			}
			else if (rol->Nombre() == ROL_MONTICULOHUEVOS) {
				_dibujador->DibujarEntidad(_imagenMonticuloHuevos, x, y);
			}
			else if (rol->Nombre() == ROL_CERDITO) {
				Cerdito* cerdito = (Cerdito*)utilidad;

				// Ignoramos el cerdito si no tiene jugador asignado
				Jugador* propietario = cerdito->getPropietario();
				if (propietario) {
					_dibujador->DibujarEntidad(_imagenCerdito, x, y);

					// Dibujamos su catapulta
					try {
						Catapulta* catapulta = cerdito->getCatapulta();


						long int catapultaX = catapulta->getPosicion()->X();
						long int catapultaY = catapulta->getPosicion()->Y();

						_dibujador->DibujarEntidad(_imagenCatapulta,
								catapultaX,
								catapultaY);
						// Dibujamos el proximo huevo a lanzar, si existe
						Actor* proxHuevo = catapulta->getProyectil();
						if (proxHuevo) {
							// OJO repite codigo
							if (rol->Nombre() == HUEVOBLANCO) {
								_dibujador->DibujarEntidad(_imagenHuevoBlanco,
										x, y);
							}
							else if (rol->Nombre() == HUEVOPOCHE) {
								_dibujador->DibujarEntidad(_imagenHuevoPoche,
										x, y);
							}
							else if (rol->Nombre() == HUEVOCODORNIZ) {
								_dibujador->DibujarEntidad(_imagenHuevoCodorniz,
										x, y);
							}
							else if (rol->Nombre() == HUEVORELOJ) {
								_dibujador->DibujarEntidad(_imagenHuevoReloj,
										x, y);
							}
						}

						// Dibuja el nombre del jugador encima de su cerdito
						_dibujador->DibujarTexto(propietario->getNombre(),
								x, y);

						// Dibujamos el puntaje del jugador                        
						unsigned int posPuntajeY =
								y + _imagenCerdito->get_height();

						std::string puntaje;
						std::stringstream out;
						out << propietario->getPuntaje();
						puntaje = out.str();

						_dibujador->DibujarTexto(puntaje, x, posPuntajeY);
					}
					catch (Excepcion& pEx) {
						// Manejar error
					}
				}
			}
			else if (rol->Nombre() == ROL_CEREZA) {
				_dibujador->DibujarEntidad(_imagenCereza, x, y);
			}
			else if (rol->Nombre() == ROL_MANZANA) {
				_dibujador->DibujarEntidad(_imagenManzana, x, y);
			}
			else if (rol->Nombre() == ROL_BANANA) {
				_dibujador->DibujarEntidad(_imagenBanana, x, y);
			}
			else if (rol->Nombre() == ROL_PISO) {
				Piso* piso = (Piso*)utilidad;
				_DibujarPiso(piso->getVectorPosiciones());
			}
		}
		_mutex.unlock();
	}
}

void LienzoJuego::_DibujarPiso(
		const std::vector<Posicion*>& vectorPosiciones) {
	unsigned int size = vectorPosiciones.size();

	if (size > 1) {
		for (unsigned int i = 0; i < (size - 1); ++i) {
			Posicion* posicion1 = vectorPosiciones[i];
			Posicion* posicion2 = vectorPosiciones[i + 1];
			unsigned int x1 = posicion1->X();
			unsigned int y1 = posicion1->Y();
			unsigned int x2 = posicion2->X();
			unsigned int y2 = posicion2->Y();
			_dibujador->DibujarLinea(x1, y1, x2, y2);
		}
	}
}

void LienzoJuego::SetPartida(Partida* partida) {
	_mutex.lock();
	if (partida != NULL) {
		if (_partida) {
			delete _partida;
		}
		_partida = partida; // @todo: Manejar error
	}
	_mutex.unlock();
}

bool LienzoJuego::on_timeout() {
	// Obliga a la ventana a redibujarse
	Glib::RefPtr<Gdk::Window> window = get_window();

	if (window) {
		Gdk::Rectangle rectangulo(0, 0, get_allocation().get_width(),
				get_allocation().get_height());
		window->invalidate_rect(rectangulo, false);
	}
	return true;
}

bool LienzoJuego::on_button_press_event(GdkEventButton* event) {
	unsigned int x = (unsigned int)event->x;
	unsigned int y = (unsigned int)event->y;

	Posicion pos(x, y);
	_cliente->atacar(&pos);
}

LienzoJuego::~LienzoJuego() {
	delete _dibujador;
}